package org.testframe;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 流程启动器
 *
 * @author 丁常磊
 * @date 2023/11/17 9:51
 */

public class FlowBootStarter {

    private ScheduledExecutorService executorService;

    private int frameTime;

    /**
     * 0 初始化
     * 1 已启动
     * 2 已关闭
     */
    private int state = 0;

    /**
     * 最大并行数量
     */
    private final int maxParallelNumber;


    private final List<ScheduledFuture<?>> tasks = new ArrayList<>();

    private volatile TaskHolder taskHolder = new TaskHolder();

    /**
     * 流程池
     */
    private final FlowPool flowPool = new FlowPool();


    /**
     * 创建一个启动器
     *
     * @param executorCount      执行任务线程数. 该数值会影响同时执行任务的数量
     * @param executorNamePrefix 执行线程名称前缀
     * @param maxRunningCount  最大在执行任务数
     * @param frameTime          帧时间间隔
     * @return
     */
    public static FlowBootStarter create(String executorNamePrefix, int executorCount, int maxRunningCount, int frameTime) {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        FlowBootStarter flowBootStarter = new FlowBootStarter(maxRunningCount);
        flowBootStarter.executorService = Executors.newScheduledThreadPool(executorCount, r -> new Thread(r, executorNamePrefix + atomicInteger.addAndGet(1)));

        flowBootStarter.frameTime = frameTime;
        return flowBootStarter;
    }


    /**
     * 线程名称前缀为 自动化测试
     * 核心线程数为CPU核心数的两倍
     * @param maxRunningCount
     * @param frameTime
     * @return
     */
    public static FlowBootStarter create(int maxRunningCount, int frameTime) {
        return create("自动化测试-", Runtime.getRuntime().availableProcessors() * 2, maxRunningCount, frameTime);
    }



    private FlowBootStarter(int maxParallelNumber) {
        this.maxParallelNumber = maxParallelNumber;
    }

    public synchronized void submit(Flow flow) {
        //提交一个流程
        if (state == 1) {
            flow.bindBootStarter(this);
            flowPool.addFlow(flow);
        } else {
            throw new IllegalStateException("流程未启动或已终止 [" + state + "]");
        }
    }

    /**
     * 创建一个子进程
     *
     * @return
     */
//    public FlowBootStarter createSubBootStarter() {
//
//        //该进程共享父进程. 随父进程销毁
//        FlowBootStarter bootStarter = new FlowBootStarter(1);
//        bootStarter.frameTime = this.frameTime;
//        bootStarter.executorService = this.executorService;
//        return bootStarter;
//
//    }


    public synchronized void start() {
        if (state == 0) {
            state = 1;
            for (int z = 0; z < maxParallelNumber; z++) {
                ScheduledFuture<?> scheduledFuture = executorService.scheduleWithFixedDelay(() -> {

                    //如果状态不是1 则终止
                    if (state != 1) {
                        return;
                    }

                    //获取当前任务执行情况
                    TaskHolder th = FlowBootStarter.this.taskHolder;


                    //补充任务数量
                    if (th.currentRunningFlowNumber < maxParallelNumber) {
                        synchronized (th) {
                            if (th.currentRunningFlowNumber < maxParallelNumber) {
                                while (true) {
                                    Flow flow = flowPool.getFlow();
                                    if (flow == null) {
                                        break;
                                    }
                                    th.currentRunningFlows.add(flow);
                                    th.currentRunningFlowNumber++;
                                    if (th.currentRunningFlowNumber >= maxParallelNumber) {
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    Random random = new Random();
                    Flow flow;
                    //从在执行任务中随机获取一个任务
                    synchronized (th) {
                        if (th.currentRunningFlows.size() == 0) {
                            return;
                        }
                        int i = random.nextInt(th.currentRunningFlows.size());
                        flow = th.currentRunningFlows.remove(i);
                    }


                    boolean end = flow.isEnd();

                    //执行下一步操作
                    if (!end) {
                        flow.next();
                        end = flow.isEnd();
                    }

                    if (end) {
                        flow.runFinally();
                        //如果流程结束
                        //不再放回
                        synchronized (th) {
                            th.currentRunningFlowNumber--;
                        }
                    } else {
                        //如果未结束. 重新放回
                        synchronized (th) {
                            th.currentRunningFlows.add(flow);
                        }
                    }

                }, frameTime, frameTime, TimeUnit.MILLISECONDS);
                tasks.add(scheduledFuture);
            }

        }
    }

    /**
     * 取消当前执行任务
     */
    public synchronized void cancel() {
        if (state == 1) {
            for (ScheduledFuture<?> task : tasks) {
                task.cancel(false);
            }
            //所有在执行的任务被重置
            taskHolder = new TaskHolder();
            //状态重置为0
            state = 0;
        }
    }

    public synchronized void stop() {
        if (state == 1) {
            executorService.shutdownNow();
        }
    }

    public int getCurrentRunningFlowNumber() {
        return taskHolder.currentRunningFlowNumber;
    }

    private static class TaskHolder {

        /**
         * 当前运行中的数量
         */
        private final List<Flow> currentRunningFlows = new ArrayList<>();

        /**
         * 当前执行中的任务数量
         */

        private volatile int currentRunningFlowNumber = 0;


    }


}
